﻿using DiffisionWithDecomposition;
using lopet.data;
using lopet.Repositories;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Diffusion2ZoneSolution
{
    public class ZonedCommunication : Communication
    {        
        public Cell Zone0 = new Cell(new Point(SimParameters.XCoordinateOfCellPosition, SimParameters.YCoordinateOfCellPosition, SimParameters.ZCoordinateOfCellPosition), 12.07);
        private double _zoneRatio;               
 
        public ZonedCommunication() : base()
        {
            _zoneRatio = SimParameters.StepSize / SimParameters.Zone0Stepsize;

            Simulation.Instance.EnqueueEvent(
                new Event(Time.Instance.GetTimeAfterNanoSeconds(0), () => MoveMoleculesInZone1()));
        }

        public void MoveMoleculesInZone1()
        {
            Parallel.For(0, Molecules.Count(), i =>
            {
                if (!Molecules[i].Absorbed && !Molecules[i].Decomposed)
                {
                    if (Zone0.IsMoleculeInside(Molecules[i]))
	                {
                        Molecules[i].IsInZone0 = true;
                        Zone0.AbsorbMolecule();
                    }
                    else
                    {
                        Molecules[i].IsInZone0 = false;                        
                    }

                    if (Molecules[i].IsInZone0 == false)
                    {
                        Molecules[i].Point = Molecules[i].CalculateNextPosition(SimParameters.StepSize);
                        var inside = Cell.IsMoleculeInside(Molecules[i]);
                        if (inside)
                        {
                            Cell.AbsorbMolecule();
                            Molecules[i].Absorbed = false;
                        }
                    }
                }
            });

            Simulation.Instance.EnqueueEvent(
                new Event(Time.Instance.GetTimeAfterNanoSeconds((int)(SimParameters.TimeTick * _zoneRatio)), () => MoveMoleculesInZone1()));
        }
      
        public override void ReportCurrentStuff()
        {
            Time.Instance.PrintTimeInSeconds();
            var molecules = Molecules.Where(m => m.Absorbed == false && m.Decomposed == false);            
            Console.WriteLine("Active Molecule Count " + molecules.Count());
            var zone0Molecues = molecules.Where(m => Zone0.IsMoleculeInside(m) == true);
            Console.WriteLine("zone0 Molecule Count " + zone0Molecues.Count());
                       
            //var mu = ShannonsMutualInformation.MutualInformation(NumberOf0sSent, NumberOf1sSent,
            //    NumberOf1sCorrectlyReceived, NumberOf0sCorrectlyReceived);

            //Console.WriteLine("0s = " + NumberOf0sSent);
            //Console.WriteLine("1s = " + NumberOf1sSent);
            //Console.WriteLine("1cr = " + NumberOf1sCorrectlyReceived);
            //Console.WriteLine("0cr = " + NumberOf0sCorrectlyReceived);

            //Console.WriteLine("I = " + mu);
            if (_streamWiter != null)
            {
                _streamWiter.Flush();                
            }

            Simulation.Instance.EnqueueEvent(
                new Event(Time.Instance.GetTimeAfterNanoSeconds(SimParameters.ReportInterval), () => ReportCurrentStuff()));
        }
        
        public override void DoOnTimeTick() // move only molecules inside the zone0
        {
            Parallel.For(0, Molecules.Count(), i =>
            {
                if (!Molecules[i].Absorbed && !Molecules[i].Decomposed && Molecules[i].IsInZone0)
                {
                    Molecules[i].Point = Molecules[i].CalculateNextPosition(SimParameters.Zone0Stepsize);
                    var inside = Cell.IsMoleculeInside(Molecules[i]);
                    if (inside)
                    {
                        Cell.AbsorbMolecule();
                        Molecules[i].Absorbed = false;
                    }
                }
            });

            //Console.WriteLine(Cell.NumberOfAbsorbedMolecules + " " + Time.Instance.Now);
            //Console.WriteLine(Molecules.Count(m => m.Decomposed == false) + " " + Time.Instance.Now);

            //Console.WriteLine(Molecules[65].Point.X + " " + Molecules[65].Point.Y + " " + Molecules[65].Point.Z);
        }
    }
}
